package com.xbongbong.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ProductConstant;
import com.xbongbong.saas.domain.entity.BusinessProductEntity;
import com.xbongbong.saas.domain.entity.BusinessUnitProductEntity;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import org.apache.commons.collections4.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author 吴峰
 * @date 2021/07/15 15:19
 */
public class ProductUtil {

    /**
     * 出入库单采用的是批量插入，导致序列号相关数据丢失，因此在此处进行赋值，以便于工作流等相关业务可使用序列号相关数据
     * 设置不存入关联产品表中的数据
     * @param productArray 关联产品源数据
     * @param product 已存入到关联产品表的数据，会保存到工作流的上下文中
     */
    public static void setProductSeq(JSONArray productArray, JSONArray product) {
        if (CollectionUtils.isNotEmpty(productArray)) {
            Map<Integer, JSONObject> seqKeyMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (int i = 0; i < productArray.size(); i++) {
                JSONObject productData = productArray.getJSONObject(i);
                JSONArray seqArray = productData.getJSONArray(ProductConstant.SEQ);
                if (productSeqIsEmpty(productData, seqArray)) {
                    // 未开启序列号或者序列号为空
                    continue;
                }
                JSONObject data = new JSONObject();
                data.put(ProductConstant.SEQ, seqArray);
                data.put(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr(), productData.getIntValue(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr()));
                seqKeyMap.put(i, data);
            }
            for (int i = 0; i < product.size(); i++) {
                if (seqKeyMap.containsKey(i)) {
                    JSONObject productData = product.getJSONObject(i);
                    productData.putAll(seqKeyMap.get(i));
                }
            }
        }
    }


    public static boolean productSeqIsEmpty(JSONObject productData, JSONArray seqArray) {
        return  BasicConstant.ZERO.equals(productData.getIntValue(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr())) || (Objects.isNull(seqArray) || seqArray.isEmpty());
    }

    /**
     * 减去已出库产品
     * @param outstockProductEntityList 入库产品
     * @param businessProductEntityList 关联单据产品
     * @return 剩余未出库产品
     * @throws XbbException
     */
    public static Map<String,Double> subtractOutstock(List<OutstockProductEntity> outstockProductEntityList, List<BusinessProductEntity> businessProductEntityList, boolean needMerge) {
        Map<String,Double> businessProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (BusinessProductEntity entity : businessProductEntityList){
            String key;
            if (needMerge) {
                key = entity.getProductId().toString();
            } else {
                key = entity.getProductId() + "_" + entity.getId();
            }
            Double num  = businessProductMap.getOrDefault(key,0D);
            num += entity.getProductNum();
            businessProductMap.put(key,num);
        }
        for (OutstockProductEntity entity : outstockProductEntityList){
            String key;
            if (needMerge) {
                key = entity.getProductId().toString();
            } else {
                key = entity.getProductId() + "_" + entity.getRefProductId();
            }
            if (businessProductMap.containsKey(key)){
                Double num = businessProductMap.get(key);
                businessProductMap.put(key,Arith.sub(num,entity.getProductNum()));
            }
        }
        return businessProductMap;
    }

    /**
     * 减去已入库产品
     * @param instockProductEntityList 入库产品
     * @param businessProductEntityList 关联单据产品
     * @return 剩余未入库产品
     * @throws XbbException
     */
    public static Map<String,Double> subtractInstock(List<InstockProductEntity> instockProductEntityList, List<BusinessProductEntity> businessProductEntityList, boolean needMerge) throws XbbException {
        Map<String,Double> businessProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (BusinessProductEntity entity : businessProductEntityList){
            String key;
            if (needMerge) {
                key = entity.getProductId().toString();
            } else {
                key = entity.getProductId() + "_" + entity.getId();
            }
            Double num  = businessProductMap.getOrDefault(key,0D);
            num += entity.getProductNum();
            businessProductMap.put(key,num);
        }
        for (InstockProductEntity entity : instockProductEntityList){
            String key;
            if (needMerge) {
                key = entity.getProductId().toString();
            } else {
                key = entity.getProductId() + "_" + entity.getRefProductId();
            }
            if (businessProductMap.containsKey(key)){
                Double num = businessProductMap.get(key);
                businessProductMap.put(key,Arith.sub(num,entity.getProductNum()));
            }
        }
        return businessProductMap;
    }

    /**
     * 剩余未出入库数量 与 出入库数量 的校验
     * @param overOutstock 超发出库
     * @param unStockMap 剩余未出入库数量
     * @param productNumMap 当前出入库数量(页面上用户填写的数量)
     * @param pageProductMap 名称对应map
     * @param errMsg 错误提示
     * @throws XbbException 错误提示 大于未出入库数量
     */
    public static void stockProductNumLegalCheck(boolean overOutstock, Map<String, Double> unStockMap, Map<String, Double> productNumMap, Map<Long, String> pageProductMap, String errMsg) throws XbbException {
        for (Map.Entry<String,Double> entry : productNumMap.entrySet()){
            String key = entry.getKey();
            Double productNum = entry.getValue();
            if (unStockMap.containsKey(key)){
                int flag = Arith.compare(unStockMap.get(key),productNum);
                if (flag < 0){
                    if (key.contains("_")) {
                        Long productId = Long.valueOf(key.split("_")[0]);
                        if (overOutstock) {
                            unStockMap.put(key, 0D);
                        } else {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,pageProductMap.get(productId) + errMsg);
                        }
                    } else {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,pageProductMap.get(Long.valueOf(key)) + errMsg);
                    }
                }else if (flag == 0){
                    unStockMap.put(key, 0D);
                }else {
                    unStockMap.put(key,Arith.sub(unStockMap.get(key),productNum));
                }
            }else {
                if (key.contains("_")) {
                    Long productId = Long.valueOf(key.split("_")[0]);
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,pageProductMap.get(productId) + errMsg);
                } else {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,pageProductMap.get(Long.valueOf(key)) + errMsg);
                }
            }
        }
    }

    /**
     * 上游单据产品数量 与 已出入库数量 的校验
     *
     * @param isOverOutstockOpen 超发出库
     * @param downstreamBusiness 下游单据产品数量
     * @param upstreamBusiness 上游单据产品数量
     * @param pageProductMap 名称对应map
     * @param errMsg 错误提示
     * @throws XbbException 错误提示 小于出入库数量
     * @return 以出入完成
     */
    public static Boolean upstreamDocumentsProductNumLegalCheck(boolean isOverOutstockOpen, Map<String, Double> downstreamBusiness, Map<String, Double> upstreamBusiness, Map<Long, String> pageProductMap, String errMsg) throws XbbException {
        StringBuilder errStr = new StringBuilder();
        for (Map.Entry<String,Double> entry : downstreamBusiness.entrySet()){
            String key = entry.getKey();
            Double dbNum = entry.getValue();
            long productId;
            if (key.contains("_")) {
                productId = Long.parseLong(key.split("_")[0]);
            } else {
                productId = Long.parseLong(key);
            }
            if (upstreamBusiness.containsKey(key)){
                int flag = Arith.compare(upstreamBusiness.get(key), dbNum);
                if (flag < 0) {
                    if (!isOverOutstockOpen) {
                        errStr.append(pageProductMap.get(productId)).append(errMsg).append(" ");
                        // throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,pageProductMap.get(productId) + errMsg);
                    } else {
                        upstreamBusiness.put(key, 0D);
                    }
                } else if (flag == 0){
                    upstreamBusiness.put(key, 0D);
                } else {
                    upstreamBusiness.put(key, Arith.sub(upstreamBusiness.get(key), dbNum));
                }
            } else {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, pageProductMap.get(productId) + errMsg);
            }
        }
        if (!Objects.equals(errStr.length(),0)){
            throw  new XbbException(SystemErrorCodeEnum.API_ERROR_100001,errStr.toString());
        }
        boolean allZero = true;
        for (Map.Entry<String, Double> entry : upstreamBusiness.entrySet()) {
            if (!Objects.equals(entry.getValue(), 0D)) {
                allZero = false;
                break;
            }
        }
        return upstreamBusiness.size() == 0 || allZero;
    }

    public static void setBusinessUnit(JSONObject jsonObject, BusinessUnitProductEntity businessUnitProductEntity) {
        businessUnitProductEntity.setBusinessUnit(jsonObject.getLong(SelectProductEnum.BUSINESS_UNIT.getAttr()));
        businessUnitProductEntity.setRate(jsonObject.getDouble(SelectProductEnum.RATE.getAttr()));
        businessUnitProductEntity.setGroupId(jsonObject.getLong(SelectProductEnum.UNIT_GROUP.getAttr()));
        businessUnitProductEntity.setBusinessNum(jsonObject.getDouble(SelectProductEnum.BUSINESS_NUM.getAttr()));
        JSONObject priceData = new JSONObject();
        priceData.put(SelectProductEnum.PRICE.getAttr(), jsonObject.get(SelectProductEnum.BUSINESS_PRICE.getAttr()));
        priceData.put(SelectProductEnum.COST.getAttr(), jsonObject.get(SelectProductEnum.BUSINESS_COST.getAttr()));
        priceData.put(SelectProductEnum.SELLING_PRICE.getAttr(), jsonObject.get(SelectProductEnum.BUSINESS_SELLING_PRICE.getAttr()));
        priceData.keySet().removeIf(key -> Objects.isNull(priceData.get(key)));
        businessUnitProductEntity.setPriceData(priceData.isEmpty() ? null : priceData);
        jsonObject.remove(ProductEnum.ENABLE_MULTI_UNIT.getSaasAttr());
        jsonObject.remove(SelectProductEnum.BUSINESS_UNIT.getAttr());
        jsonObject.remove(SelectProductEnum.RATE.getAttr());
        jsonObject.remove(SelectProductEnum.UNIT_GROUP.getAttr());
        jsonObject.remove(SelectProductEnum.BUSINESS_NUM.getAttr());
        jsonObject.remove(SelectProductEnum.BUSINESS_PRICE.getAttr());
        jsonObject.remove(SelectProductEnum.BUSINESS_COST.getAttr());
        jsonObject.remove(SelectProductEnum.BUSINESS_SELLING_PRICE.getAttr());
        jsonObject.remove(ProductConstant.UNIT_RATE);
        jsonObject.remove(ProductConstant.TRANSFORM_UNIT_RATE);
        jsonObject.remove(ProductConstant.PRICE);
    }
}
